﻿/*
 * UdpServer.h
 */

#ifndef __GDK_UDPSERVER_H__
#define __GDK_UDPSERVER_H__

#include <gdk/net/Socket.h>
#include <gdk/net/chksum.h>
#include <gdk/core/Memory.h>
#include <gdk/core/Thread.h>
#include <gdk/core/MemoryStream.h>
#include <gdk/core/Uuid.h>
#include <gdk/core/Mutex.h>
#include <gdk/core/Time.h>
#include <vector>
#include <map>
#include <list>



namespace gdk
{




////////////////////////////////////////
class GDK_NET_EXPORT UdpServer : public Socket
{
	DECLARE_CLASS_HANDLE(UdpServer)
	DECLARE_CLASS_INSTANCE(UdpServer)


public:
	class GDK_NET_EXPORT UdpConnection : virtual public Unknown
	{
		DECLARE_CLASS_HANDLE(UdpConnection)
		DECLARE_CLASS_INSTANCE(UdpConnection)

	public:
		enum ConnectionState
		{
			INVALID,		//无效
			CONNECTING,		//连接中
			CONNECTED,		//连接
			CONNECTTIMEOUT,	//连接超时
			CLOSED,			//连接关闭
			ABORT,			//连接中断
		};

		enum
		{
			ID_NULL = 0xffff
		};

		enum
		{
			OP_NULL,
			OP_CONNECT,
			OP_ACCEPT,
			OP_DATA,
			OP_CLOSE,
			OP_ALIVE,
			OP_RESET,
			OP_KNOCK,
			OP_INCOMING,
			OP_BROADCAST,
			OP_TRANSMIT,
			OP_USERDATA,
		};

		enum
		{
			/*
				1500. The largest Ethernet packet size; it is also the default value.
						This is the typical setting for non-PPPoE, non-VPN connections.
						The default value for NETGEAR routers, adapters and switches.
				1492. The size PPPoE prefers.
				1472. Maximum size to use for pinging. (Bigger packets are fragmented.)
				1468. The size DHCP prefers.
				1460. Usable by AOL if you don't have large email attachments, etc.
				1430. The size VPN and PPTP prefer.
				1400. Maximum size for AOL DSL.
				576. Typical value to connect to dial-up ISPs.
			*/
			PACKAGE_SIZE			= 1400 - 28, /* 网络MTU(最大传输单元，家庭的ADSL是1500-8，电信和联通之间的MTU是1500-20)*/
			PACKAGE_HEAD_SIZE		= 4, /*数据包头大小*/
			SESSION_HEAD_SIZE		= 8, /*会话数据包头大小*/
			PACKAGE_MAX_DATA_SIZE	= PACKAGE_SIZE\
										- (PACKAGE_HEAD_SIZE + sizeof(Uuid) + sizeof(struct in_addr) + sizeof(uint16_t)) /*TransmitPkg 数据头大小*/\
										- (PACKAGE_HEAD_SIZE + SESSION_HEAD_SIZE) /*SessionPkg 数据头大小*/,
		};

		//------------------------------------------------------
#if defined(_WIN32)
#		pragma pack(push, 1)
#endif
		struct Package
		{
			enum {
				PACKAGE_HEAD_SIZE = UdpConnection::PACKAGE_HEAD_SIZE,
			};


#define	PACKAGE_OPERATE_MASK      0xf800
#define	PACKAGE_OPERATE_OFFSET    11
#define	PACKAGE_DATA_SIZE_MASK    0x07ff
#define	PACKAGE_DATA_SIZE_OFFSET  0
/*
			uint16_t	_operate:5;
			uint16_t	_dataSize:11;
*/
			uint16_t	_reserved;
			uint16_t	_checksum;


		private:
			__INLINE__ void setData(uint16_t i, int mask, int offset)
			{
				_reserved = hton(uint16_t((ntoh(_reserved) & ~mask) | ((i << offset) & mask)));
			}
			__INLINE__ uint16_t getData(int mask, int offset) const
			{
				return uint16_t((ntoh(_reserved) & mask) >> offset);
			}
		public:
			__INLINE__ Package(void)
			{
				_checksum = 0;
			}
			__INLINE__ uint16_t checksum(void)
			{
				return(_checksum = chksum(this, PACKAGE_HEAD_SIZE + getDataSize()));
			}
			__INLINE__ void setOperate(uint16_t i)
			{
				setData(i, PACKAGE_OPERATE_MASK, PACKAGE_OPERATE_OFFSET);
			}
			__INLINE__ uint16_t getOperate(void) const
			{
				return getData(PACKAGE_OPERATE_MASK, PACKAGE_OPERATE_OFFSET);
			}
			__INLINE__ void setDataSize(uint16_t i)
			{
				setData(i, PACKAGE_DATA_SIZE_MASK, PACKAGE_DATA_SIZE_OFFSET);
			}
			__INLINE__ uint16_t getDataSize(void) const
			{
				return getData(PACKAGE_DATA_SIZE_MASK, PACKAGE_DATA_SIZE_OFFSET);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		//------------------------------------------------------
		struct SessionPkg : public Package
		{
			enum {
				SESSION_HEAD_SIZE = UdpConnection::SESSION_HEAD_SIZE,
			};

		private:
			uint16_t	_fromId;
			uint16_t	_targetId;
			uint32_t	_timestamp;

		public:
			__INLINE__ SessionPkg(void)
			{
				setTimestamp(getTimeTick());
			}
			__INLINE__ void setFromId(uint16_t i)
			{
				_fromId = hton(i);
			}
			__INLINE__ uint16_t getFromId(void) const
			{
				return ntoh(_fromId);
			}
			__INLINE__ void setTargetId(uint16_t i)
			{
				_targetId = hton(i);
			}
			__INLINE__ uint16_t getTargetId(void) const
			{
				return ntoh(_targetId);
			}
			__INLINE__ void setTimestamp(uint32_t timestamp)
			{
				_timestamp = hton(timestamp);
			}
			__INLINE__ uint32_t getTimestamp(void) const
			{
				return ntoh(_timestamp);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct ConnectPkg : public SessionPkg
		{
		private:
			Uuid		_socketIdFrom;
			Uuid		_socketIdTarget;

		public:
			__INLINE__ ConnectPkg(void)
			{
				setOperate(OP_CONNECT);
				setDataSize(sizeof(ConnectPkg) - PACKAGE_HEAD_SIZE);
			}
			__INLINE__ void setFromSocketId(const Uuid &socketId)
			{
				_socketIdFrom = hton(socketId);
			}
			__INLINE__ Uuid getFromSocketId(void) const
			{
				return ntoh(_socketIdFrom);
			}
			__INLINE__ void setTargetSocketId(const Uuid &socketId)
			{
				_socketIdTarget = hton(socketId);
			}
			__INLINE__ Uuid getTargetSocketId(void) const
			{
				return ntoh(_socketIdTarget);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct AcceptPkg : public SessionPkg
		{
		private:
			Uuid		_socketIdFrom;
			Uuid		_socketIdTarget;

		public:
			__INLINE__ AcceptPkg(void)
			{
				setOperate(OP_ACCEPT);
				setDataSize(sizeof(AcceptPkg) - PACKAGE_HEAD_SIZE);
			}
			__INLINE__ void setFromSocketId(const Uuid &socketId)
			{
				_socketIdFrom = hton(socketId);
			}
			__INLINE__ Uuid getFromSocketId(void) const
			{
				return ntoh(_socketIdFrom);
			}
			__INLINE__ void setTargetSocketId(const Uuid &socketId)
			{
				_socketIdTarget = hton(socketId);
			}
			__INLINE__ Uuid getTargetSocketId(void) const
			{
				return ntoh(_socketIdTarget);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct DataPkg : public SessionPkg
		{
			uint8_t		_buffer[PACKAGE_MAX_DATA_SIZE];

		public:
			__INLINE__ DataPkg(void)
			{
				setOperate(OP_DATA);
			}
			__INLINE__ ssize_t putData(void const* data, ssize_t dataSize)
			{
				if (dataSize > static_cast<ssize_t>(sizeof(_buffer)))
					dataSize = sizeof(_buffer);
				else if (dataSize < 0)
					dataSize = 0;

				setDataSize(uint16_t(SESSION_HEAD_SIZE + dataSize));
				memCopy(_buffer, data, dataSize);

				return dataSize;
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct ClosePkg : public SessionPkg
		{
		public:
			__INLINE__ ClosePkg(void)
			{
				setOperate(OP_CLOSE);
				setDataSize(sizeof(ClosePkg) - PACKAGE_HEAD_SIZE);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct AlivePkg : public SessionPkg
		{
		public:
			__INLINE__ AlivePkg(void)
			{
				setOperate(OP_ALIVE);
				setDataSize(sizeof(AlivePkg) - PACKAGE_HEAD_SIZE);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct ResetPkg : public SessionPkg
		{
		private:
			Uuid		_socketIdFrom;

		public:
			__INLINE__ ResetPkg(void)
			{
				setOperate(OP_RESET);
				setDataSize(sizeof(ResetPkg) - PACKAGE_HEAD_SIZE);
			}
			__INLINE__ void setFromSocketId(const Uuid &socketId)
			{
				_socketIdFrom = hton(socketId);
			}
			__INLINE__ Uuid getFromSocketId(void) const
			{
				return ntoh(_socketIdFrom);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		//------------------------------------------------------
		struct KnockPkg : public Package
		{
		private:
			struct  in_addr	_addr;
			u_short			_port;

		public:
			__INLINE__ KnockPkg(void)
			{
				setOperate(OP_KNOCK);
				setDataSize(sizeof(KnockPkg) - PACKAGE_HEAD_SIZE);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct IncomingPkg : public Package
		{
		public:
			__INLINE__ IncomingPkg(void)
			{
				setOperate(OP_INCOMING);
				setDataSize(sizeof(IncomingPkg) - PACKAGE_HEAD_SIZE);
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct BroadcastPkg : public Package
		{
			enum {
				PACKAGE_MAX_BROADCAST_DATA_SIZE = PACKAGE_HEAD_SIZE + SESSION_HEAD_SIZE + PACKAGE_MAX_DATA_SIZE,
			};

			uint8_t		_buffer[PACKAGE_MAX_BROADCAST_DATA_SIZE];

		public:
			__INLINE__ BroadcastPkg(void)
			{
				setOperate(OP_BROADCAST);
			}
			__INLINE__ ssize_t putData(void const* data, ssize_t dataSize)
			{
				if (dataSize > static_cast<ssize_t>(sizeof(_buffer)))
					dataSize = sizeof(_buffer);
				else if (dataSize < 0)
					dataSize = 0;

				setDataSize(uint16_t(dataSize));
				memCopy(_buffer, data, dataSize);

				return dataSize;
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct TransmitPkg : public Package
		{
			enum {
				PACKAGE_TRANSMIT_HEAD_SIZE = sizeof(Uuid) + sizeof(struct in_addr) + sizeof(uint16_t),
				PACKAGE_MAX_TRANSMIT_DATA_SIZE = PACKAGE_HEAD_SIZE + SESSION_HEAD_SIZE + PACKAGE_MAX_DATA_SIZE,
			};

		private:
			Uuid			_socketIdPeer;
			struct __in_addr _address;
			uint16_t		_port;
		public:
			char			_buffer[PACKAGE_MAX_TRANSMIT_DATA_SIZE];

		public:
			__INLINE__ TransmitPkg(void)
			{
				setOperate(OP_TRANSMIT);
			}
			__INLINE__ ssize_t putData(void const* data, ssize_t dataSize)
			{
				if (dataSize > static_cast<ssize_t>(sizeof(_buffer)))
					dataSize = sizeof(_buffer);
				else if (dataSize < 0)
					dataSize = 0;

				setDataSize((uint16_t)(PACKAGE_TRANSMIT_HEAD_SIZE + dataSize));
				memCopy(_buffer, data, dataSize);

				return dataSize;
			}
			__INLINE__ ssize_t getBufferSize(void) const
			{
				return getDataSize() - PACKAGE_TRANSMIT_HEAD_SIZE;
			}
			__INLINE__ void setPeerSocketId(const Uuid &socketId)
			{
				_socketIdPeer = hton(socketId);
			}
			__INLINE__ Uuid getPeerSocketId(void) const
			{
				return ntoh(_socketIdPeer);
			}
			__INLINE__ void setAddress(const struct __sockaddr_in &addr)
			{
				memcpy(&_address, SA_ADDR(addr), sizeof(_address));
				_port = hton(SA_PORT(addr));
			}
			__INLINE__ void getAddress(struct __sockaddr_in &addr)
			{
				SA_SET_ADDR(addr, &_address);
				SA_SET_PORT(addr, ntoh(_port));
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
		struct UserDataPkg : public Package
		{
			enum {
				PACKAGE_MAX_USER_DATA_SIZE = PACKAGE_SIZE - PACKAGE_HEAD_SIZE,
			};

			uint8_t		_buffer[PACKAGE_MAX_USER_DATA_SIZE];

		public:
			__INLINE__ UserDataPkg(void)
			{
				setOperate(OP_USERDATA);
			}
			__INLINE__ ssize_t putData(void const* data, ssize_t dataSize)
			{
				if (dataSize > static_cast<ssize_t>(sizeof(_buffer)))
					dataSize = sizeof(_buffer);
				else if (dataSize < 0)
					dataSize = 0;

				setDataSize(uint16_t(dataSize));
				memCopy(_buffer, data, dataSize);

				return dataSize;
			}
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
		;
#if defined(_WIN32)
#		pragma pack(pop)
#endif
		//------------------------------------------------------


	private:
		__sockaddr_in		_peerAddress;
		Uuid				_peerSocketId;

		UdpServer::Handle	_udpServer;
		uint16_t			_localId;
		uint16_t			_targetId;

		uint32_t			_aliveTimeOut;
		int					_aliveTryCount;
		uint32_t			_inActiveTime;
		uint32_t			_outActiveTime;

		ConnectionState		_connectionState;
		uint32_t			_connectTime;
		uint32_t			_timestamp;

		enum
		{
			CS_UNKNOWN,	//未知
			CS_TRANSMIT,//转发
			CS_DIRECT,	//直接连接
		}					_connectStyle;

	protected:
		UdpConnection(void);
		__INLINE__ ~UdpConnection(void)
		{
			close();
		}

	public:
		__INLINE__ UdpServer* getUdpServer(void) const
		{
			return _udpServer;
		}
		__INLINE__ uint16_t getLocalId(void) const
		{
			return _localId;
		}
		__INLINE__ uint16_t getTargetId(void) const
		{
			return _targetId;
		}
		__INLINE__ bool isInvalid(void) const
		{
			return _udpServer == NULL;
		}
		__INLINE__ void getPeerName(struct __sockaddr_in &addr) const
		{
			memCopy(&addr, &_peerAddress, sizeof(struct __sockaddr_in));
		}
		String  getPeerName(void) const;
		__INLINE__ void getPeerName(String &ip, uint16_t &port) const
		{
			char buf[128]; buf[0] = 0;
			ip = StringConvert(inet_ntop(SA_FAMILY(_peerAddress), SA_ADDR(_peerAddress), buf, sizeof(buf)));
			port = SA_PORT(_peerAddress);
		}
		__INLINE__ Uuid const& getPeerSocketId(void) const
		{
			return _peerSocketId;
		}

		__INLINE__ void setKeepAliveTime(uint32_t timeOut, int tryCount)
		{
			/* 区间在 1~60 秒之间 */
			if (timeOut <= 1000) _aliveTimeOut = 1000;
			else if (timeOut >= 1000 * 60) _aliveTimeOut = 1000 * 60;
			else _aliveTimeOut = timeOut;

			_aliveTryCount = (tryCount <= 6) ? 6 : tryCount;
		}
		__INLINE__ void getKeepAliveTime(uint32_t &timeOut, int &tryCount) const
		{
			timeOut = _aliveTimeOut;
			tryCount = _aliveTryCount;
		}

	protected:
		__INLINE__ void setConnectionState(ConnectionState connectionState) { _connectionState = connectionState; }
	public:
		__INLINE__ ConnectionState getConnectionState(void) const { return _connectionState; }

	public:
		__INLINE__ virtual void onTick(uint32_t timeSinceLastTick)
		{
			(void)&timeSinceLastTick;
		}
		__INLINE__ virtual bool connect(UdpServer *pUdpServer, const Char *ip, unsigned short port, const Uuid & socketId = UUID_NULL)
		{
			return pUdpServer->connect(this, ip, port, socketId);
		}
		__INLINE__ virtual ssize_t receive(void *buf, ssize_t len)
		{
			if (isInvalid()) return -1;

			return _udpServer->receive(this, buf, len);
		}
		__INLINE__ virtual ssize_t send(const void *data, ssize_t len)
		{
			if (isInvalid()) return -1;

			if (_localId == ID_NULL
			||  _targetId == ID_NULL
			)  return 0;

			return _udpServer->send(this, data, len);
		}
		__INLINE__ virtual void close(void)
		{
			if (_udpServer != NULL)
			{
				_udpServer->close(this);
			}
		}


	protected:
		__INLINE__ virtual void onSend(void) {}
		__INLINE__ virtual void onReceive(void) {}

	private:
		friend class UdpServer;
	};


private:
	class Sender : public System
	{
		DECLARE_CLASS_HANDLE(Sender)
		DECLARE_CLASS_INSTANCE1(Sender,UdpServer*)

	private:
		UdpServer::Handle		_udpServer;
		Mutex					_bufferMutex;
		MemoryStream::Handle	_buffer;


	private:
		Sender(UdpServer *udpServer);

	public:
		virtual void onTick(uint32_t timeSinceLastTick);

	public:
		void write(	const UdpConnection::Package *pkg,
					const struct __sockaddr_in   *to);
	private:
		__INLINE__ int read(UdpConnection::Package *pkg,
							struct __sockaddr_in   *to,
							uint32_t               *timeStamp);
	};
	class Receiver : public System
	{
		DECLARE_CLASS_HANDLE(Receiver)
		DECLARE_CLASS_INSTANCE1(Receiver, UdpServer*)

		class RejectAddr
		{
		public:
			__sockaddr_in	addr;
			uint32_t		time;
		};
		typedef std::map<__sockaddr_in, RejectAddr> RejectAddrMap;

	private:
		UdpServer::Handle		_udpServer;
		Mutex					_bufferMutex;
		int						_signal;
		MemoryStream::Handle	_buffer;
		RejectAddrMap			_rejectAddrs;


	private:
		Receiver(UdpServer *udpServer);

	public:
		virtual void onTick(uint32_t timeSinceLastTick);

	public:
		int read(	UdpConnection::Package *pkg,
					struct __sockaddr_in   *from);
	private:
		__INLINE__ void write(	const UdpConnection::Package *pkg,
								const struct __sockaddr_in   *from);
		void reject(__sockaddr_in sa, uint32_t t);
	};

private:
	typedef UdpConnection::Handle							UdpConnectionHandle;
	typedef std::list<UdpConnectionHandle>					UdpConnectionList;
	typedef std::map<uint16_t, UdpConnectionList::iterator>	UdpConnectionMap;
	typedef std::map<String, UdpConnectionHandle>			UdpConnectionMapAccept;
	struct ConnectionLinker
	{
		Uuid				socketId;
		__sockaddr_in		addr;
		UdpConnectionList	connectionList;
	};
	typedef std::map<Uuid, ConnectionLinker>				ConnectionLinkerMap;

	UdpConnectionList				_connections;
	UdpConnectionMap				_mapConnections;
	UdpConnectionMapAccept			_mapConnectionsAccept;
	UdpConnectionList				_closedConnections;
	ConnectionLinkerMap				_mapConnectionLinker;

	__sockaddr_in					_fromAddress;
	bool							_transmitPackage;
	__sockaddr_in					_transmitAddress;
	UdpConnection::Package*			_package;
	char							_buffer[UdpConnection::PACKAGE_SIZE];

	Uuid							_socketId;
	uint16_t						_port;

	Thread::Handle					_senderThread;
	Sender::Handle					_sender;

	Thread::Handle					_receiverThread;
	Receiver::Handle				_receiver;


protected:
	UdpServer(void);
	~UdpServer(void);

private:
	ssize_t receive(UdpConnection *pUdpConnection, void *buf, ssize_t len); //接收UDP数据
	ssize_t send(UdpConnection *pUdpConnection, const void *data, ssize_t len);//发送UDP数据
	bool alive(UdpConnection *pUdpConnection); //保持UDP连接的活动
	bool close(UdpConnection *pUdpConnection); //关闭UDP连接
	bool reset(const UdpConnection::SessionPkg *pkg, const struct __sockaddr_in &addr);
	bool send(const UdpConnection::Package &pkg, const struct __sockaddr_in &to);
	void send(UdpConnection *udpConnection, const UdpConnection::Package &pkg);
	void processPackage(void *buffer, ssize_t bufferSize);
	void transmitPackage(const UdpConnection::TransmitPkg &transmitPkg);
	UdpConnection* getUdpConnection(uint16_t hLocal) const;
	void bindAddress(UdpConnection *udpConnection, uint32_t timestamp);
	bool findEqualSocketAddress(const Uuid &socketId, struct __sockaddr_in &addr) const;

public:
	bool incoming(char const *ip, uint16_t port);
	bool incoming(char const *hostname);
	bool incoming(struct __sockaddr_in const &addr);

	void peerBroadcast(const UdpConnection::Package *package);

	__INLINE__ Uuid const& getSocketId(void) const { return _socketId; }
	__INLINE__ uint16_t getPort(void) const { return _port; }

	__INLINE__ bool isBroadcastEnable(void) const
	{
		int flag = 0, size = sizeof(flag);
		getsockopt(getSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&flag, &size);
		return (flag != 0);
	}
	__INLINE__ bool setBroadcastEnable(bool flag)
	{
		int a = flag ? 1 : 0;
		return !setsockopt(getSocket(), SOL_SOCKET, SO_BROADCAST, (const char *)&a, sizeof(a));
	}
	int broadcast(uint16_t port, const void *data, int len);

	static SOCKET udpsocket(unsigned short port);

public:
	virtual void   onTick(uint32_t timeSinceLastTick);
	virtual bool   listen(unsigned short port);
	virtual void   close(void);
	virtual bool   attach(SOCKET s);
	virtual SOCKET detach(void);
	virtual bool   connect(UdpConnection *pUdpConnection, const Char *ip, unsigned short port, const Uuid & socketId = UUID_NULL); //UDP连接
	virtual bool   accept(UdpConnection *pUdpConnection);


protected:
	__INLINE__ virtual void onAccept(void)
	{
	}
	__INLINE__ virtual void onUserData(struct __sockaddr_in const &from, void const *data, int len)
	{
		(void)&from;
		(void)&data;
		(void)&len;
	}

private:
	friend class UdpConnection;
};


typedef UdpServer::UdpConnection  UdpConnection;




}//namespace gdk


#endif //__GDK_UDPSERVER_H__
